/**
 * 
 */
package org.statewalker.core;

import java.util.Map;

public class AsyncState implements IState {

    public final static IStateFactory FACTORY = new IStateFactory() {
        public IState newState(String stateKey) {
            return new AsyncState();
        }
    };

    protected String fKey;

    protected IState fParent;

    protected IProcessContext fProcessContext;

    protected Map<String, String> fProperties;

    public AsyncState() {
    }

    public final void activate(IEvent event, ICallback callback) {
        try {
            doActivate(event, callback);
        } catch (Throwable t) {
            try {
                event = handleEvent(t, "State activation failed", event);
            } finally {
                callback.finish(event);
            }
        }
    }

    public final void deactivate(IEvent event, ICallback callback) {
        try {
            doDeactivate(event, callback);
        } catch (Throwable t) {
            try {
                event = handleEvent(t, "State deactivation failed", event);
            } finally {
                callback.finish(event);
            }
        }
    }

    protected void doActivate(IEvent event, ICallback callback)
        throws Exception {
        callback.finish(event);
    }

    protected void doDeactivate(IEvent event, ICallback callback)
        throws Exception {
        callback.finish(event);
    }

    protected void doOnTransition(IState prev, IEvent event, IState next) {
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (!(obj instanceof AsyncState)) {
            return false;
        }
        AsyncState o = (AsyncState) obj;
        if (!fKey.equals(o.fKey)) {
            return false;
        }
        return fParent == null || o.fParent == null
            ? fParent == o.fParent
            : fParent.equals(o.fParent);
    }

    /**
     * @see org.statewalker.core.IState#getContext()
     */
    public IProcessContext getContext() {
        return fProcessContext;
    }

    public String getKey() {
        return fKey;
    }

    public IState getParent() {
        return fParent;
    }

    public Map<String, String> getProperties() {
        return fProperties;
    }

    public String getProperty(String propertyName) {
        return fProperties != null ? fProperties.get(propertyName) : null;
    }

    protected IEvent handleEvent(Throwable t, String message, IEvent event) {
        return new ErrorEvent(t);
    }

    @Override
    public int hashCode() {
        return fKey.hashCode();
    }

    public final void onTransition(IState prev, IEvent event, IState next) {
        try {
            doOnTransition(prev, event, next);
        } catch (Throwable t) {
            handleEvent(t, "onTransition method failed", event);
        }
    }

    /**
     * @see org.statewalker.core.IState#setContext(org.statewalker.core.IProcessContext)
     */
    public void setContext(IProcessContext context) {
        fProcessContext = context;
    }

    /**
     * @see org.statewalker.core.IState#setKey(java.lang.String)
     */
    public void setKey(String stateKey) {
        fKey = stateKey;
    }

    /**
     * @see org.statewalker.core.IState#setParent(org.statewalker.core.IState)
     */
    public void setParent(IState parent) {
        fParent = parent;
    }

    public void setProperties(Map<String, String> properties) {
        fProperties = properties;
    }

    @Override
    public String toString() {
        return fParent != null
            ? fParent.toString() + "/" + fKey.toString()
            : fKey.toString();
    }
}